/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package retrieval;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import queryterm.QueryTerm;
import util.FileListing;
import util.Timer;

/**
 *
 * @author Danang
 */
public class ListDocument {
    // Document ID, DocModel
    private HashMap<Integer,DocumentModel> listDocument;
    boolean setDocumentLength=false; // default is false except initReadDocumentLength is called
    FileListing fl;
    
    private int jumlahDokumen;
    private double avgDocumentLength;
    
    // queryHistory
    ArrayList<String> queries;
    
    public ListDocument() {
        listDocument = new HashMap<Integer, DocumentModel>();
        queries = new ArrayList<String>();
    }

    public void setDocumentStatistic(int jumlahMail, double avgLength) throws Exception {
        jumlahDokumen = jumlahMail;
        avgDocumentLength = avgLength;
    }
    
    public void initReadDocumentLength(FileListing fl) throws Exception {
        setDocumentLength = true;
        this.fl = fl;
    }
    
    
    private DocumentModel addDocumentModel(int id) {
        DocumentModel res = null;
        if (getListDocument().containsKey(id)) {
            res = getListDocument().get(id);
        } else {
            res = new DocumentModel(id);
            if (setDocumentLength) {
                try {
                    res.setDocLength(fl.getDocumentLengthFromHashMap(id));
                } catch (Exception e) {
                    System.out.println("Error set doc length "+e.getMessage());
                    System.out.println("Setting doc length to avg ");
                    res.setDocLength((long)getAvgDocumentLength());
                }
            }
            
            getListDocument().put(id, res);
        }
        return res;
    }
    
    public void addPostingListString(String token, int field, String str) {
        String qu = token+":"+field;
        if (!queries.contains(qu)) {
            queries.add(qu);
        }
        String[] split_enter = str.split("\n");
        for (String s : split_enter) {
            if (!s.isEmpty()) {
                String[] split_comma = s.split(",");
                ArrayList<Integer> arr = new ArrayList<Integer>();
                for (int i = 1; i < split_comma.length; i++) {
                    arr.add(Integer.parseInt(split_comma[i]));
                }
                DocumentModel d = addDocumentModel(Integer.parseInt(split_comma[0]));
                d.addToken(token, field, arr);
            }
        }
    }
    
    public void addQueryBerurutan(String query, int field) {
        String qu = query+":"+field;
        if (!queries.contains(qu)) {
            queries.add(qu);
        }
        //System.out.println("Searching query \""+query+"\" in field "+QueryTerm.getFieldString(field));
        Timer t = new Timer();
        String[] tokens = query.split(" ");
        Iterator iter = getListDocument().entrySet().iterator();
        while (iter.hasNext()) {
            Map.Entry pairs = (Map.Entry) iter.next();
            DocumentModel dm = (DocumentModel) pairs.getValue();
            boolean haveAllQueries = true;
            SearchConsecutive sm = new SearchConsecutive();
            for (String token : tokens) {
                if (dm.getQueryTF(token,field)==0) {
                    haveAllQueries = false;
                    break;
                }
                sm.addList(token, dm.getQueryPosition(token,field));
            }
            if (haveAllQueries) {
                sm.doSearch();
                int res = sm.getCountResult();
                if (res!=0) {
                    dm.addToken(query, field, sm.getListHasil());
                }
            }
        }
        //t.printExecution_time("Finished Searching query "+query);
    }
    
    List<DocumentModel> sortByDocID() {
        List<DocumentModel> res = new ArrayList<DocumentModel>(getListDocument().values());
        Collections.sort(res, new Comparator<DocumentModel>() {
            @Override
            public int compare(DocumentModel o1, DocumentModel o2) {
                return o1.getId()==o2.getId() ? 0 : o1.getId() > o2.getId() ? 1 : -1;
            }
            
        });
        return res;
    }
    
    
    public String toOutputFile(String query, int nTopRanked) {
        StringBuilder sb = new StringBuilder();
        List<DocumentModel> sorted = getNTopRankedDocument(nTopRanked);
        Iterator iter = sorted.iterator();
        while(iter.hasNext()) {
            DocumentModel dm = (DocumentModel) iter.next();
            sb.append(dm.toOutputFile(query));
        }
        return sb.toString();
    }
    
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        List<DocumentModel> sorted = getNTopRankedDocument(40);
        sb.append("Search results : ").append(sorted.size()).append(FileListing.newLine);
        int length = sb.length();
        HashMap<String,Integer> hasilSearch = new HashMap<String, Integer>();
        Iterator iter = sorted.iterator();
        while(iter.hasNext()) {
            DocumentModel dm = (DocumentModel) iter.next();
            sb.append(dm.toString());
            sb.append(FileListing.newLine);
            for (String q : queries) {
                String[] tmp = q.split(":");
                int field = Integer.parseInt(tmp[1]);
                String query = tmp[0];
                String add = q;
                Integer jumlahSearch;
                if (!hasilSearch.containsKey(add)) {
                    jumlahSearch = new Integer(0);
                    hasilSearch.put(add, jumlahSearch);
                } else {
                    jumlahSearch = hasilSearch.get(add);
                }
                jumlahSearch += dm.getQueryTF(query, field);
                hasilSearch.put(add, jumlahSearch);
            }
        }
        StringBuilder statistic = new StringBuilder();
        statistic.append("Statistic search results : ").append(FileListing.newLine);
        for (String q : queries) {
            String[] tmp = q.split(":");
            int field = Integer.parseInt(tmp[1]);
            String query = tmp[0];
            String add = q;
            statistic.append("Query \"").append(query).append("\" in field ").append(QueryTerm.getFieldString(field)).append(" : ").append(hasilSearch.get(add)).append(FileListing.newLine);
        }
        statistic.append(FileListing.newLine);
        sb.insert(length, statistic.toString());
        return sb.toString();
    }
    
    public int getDocumentFrequencyByQuery(String query, int field) {
        int total = 0;
        
        Iterator iter = getListDocument().entrySet().iterator();
        while (iter.hasNext()) {
            Map.Entry pairs = (Map.Entry) iter.next();
            DocumentModel dm = (DocumentModel) pairs.getValue();
            if (dm.getQueryTF(query,field)!=0) {
                total++;
            }
        }
        
        return total;
    }
    
    
    public List<DocumentModel> sortDocumentsByWeight() {
        List<DocumentModel> result = new ArrayList<DocumentModel>(getListDocument().values());
        
        Collections.sort(result, new Comparator<DocumentModel>() {
            @Override
            public int compare(DocumentModel o1, DocumentModel o2) {
                return o1.getWeight()==o2.getWeight() ? 0 : o1.getWeight()> o2.getWeight() ? -1 : 1;
            }
            
        });
        
        return result;
    }
    
    public List<DocumentModel> getNTopRankedDocument(int n) {
        List<DocumentModel> sortedList = sortDocumentsByWeight();
        List<DocumentModel> topNRanked = sortedList.subList(0, n);
        int rank = 1;
        for (DocumentModel d : topNRanked) {
            d.setRank(rank);
            rank++;
        }
        return topNRanked;
    }

    /**
     * @return the listDocument
     */
    public HashMap<Integer,DocumentModel> getListDocument() {
        return listDocument;
    }

    /**
     * @return the jumlahDokumen
     */
    public int getJumlahDokumen() {
        return jumlahDokumen;
    }

    /**
     * @return the avgDocumentLength
     */
    public double getAvgDocumentLength() {
        return avgDocumentLength;
    }

}
